home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcl
/
src-16f.lha
/
compiler
/
sset.lisp
< prev
next >
Wrap
Lisp/Scheme
|
1991-11-06
|
9KB
|
301 lines
;;; -*- Package: C; Log: C.Log -*-
;;;
;;; **********************************************************************
;;; This code was written as part of the CMU Common Lisp project at
;;; Carnegie Mellon University, and has been placed in the public domain.
;;; If you want to use this code or any part of CMU Common Lisp, please contact
;;; Scott Fahlman or slisp-group@cs.cmu.edu.
;;;
(ext:file-comment
"$Header: sset.lisp,v 1.4 91/02/20 14:59:48 ram Exp $")
;;;
;;; **********************************************************************
;;;
;;; A sparse set abstraction, implemented as a sorted linked list. We don't
;;; use bit-vectors to represent sets in flow analysis, since the universe may
;;; be quite large but the average number of elements is small. We keep the
;;; list sorted so that we can do union and intersection in linear time.
;;;
;;; Written by Rob MacLachlan
;;;
(in-package 'c)
;;;
;;; Each structure that may be placed in a SSet must include the SSet-Element
;;; structure. We allow an initial value of NIL to mean that no ordering has
;;; been assigned yet (although an ordering must be assigned before doing set
;;; operations.)
;;;
(defstruct sset-element
(number nil :type (or index null)))
(defstruct (sset (:constructor make-sset ())
(:copier nil)
(:print-function %print-sset))
(elements (list nil) :type list))
(defprinter sset
(elements :prin1 (cdr elements)))
;;; Do-Elements -- Interface
;;;
;;; Iterate over the elements in Set, binding Var to each element in turn.
;;;
(defmacro do-elements ((var set &optional result) &body body)
`(dolist (,var (cdr (sset-elements ,set)) ,result) ,@body))
;;; SSet-Adjoin -- Interface
;;;
;;; Destructively add Element to Set. If Element was not in the set, then
;;; we return true, otherwise we return false.
;;;
(proclaim '(function sset-adjoin (sset-element sset) boolean))
(defun sset-adjoin (element set)
(let ((number (sset-element-number element))
(elements (sset-elements set)))
(do ((prev elements current)
(current (cdr elements) (cdr current)))
((null current)
(setf (cdr prev) (list element))
t)
(let ((el (car current)))
(when (>= (sset-element-number el) number)
(when (eq el element)
(return nil))
(setf (cdr prev) (cons element current))
(return t))))))
;;; SSet-Delete -- Interface
;;;
;;; Destructively remove Element from Set. If element was in the set,
;;; then return true, otherwise return false.
;;;
(proclaim '(function sset-delete (sset-element sset) boolean))
(defun sset-delete (element set)
(let ((elements (sset-elements set)))
(do ((prev elements current)
(current (cdr elements) (cdr current)))
((null current) nil)
(when (eq (car current) element)
(setf (cdr prev) (cdr current))
(return t)))))
;;; SSet-Member -- Interface
;;;
;;; Return true if Element is in Set, false otherwise.
;;;
(proclaim '(function sset-member (sset-element sset) boolean))
(defun sset-member (element set)
(declare (inline member))
(not (null (member element (cdr (sset-elements set)) :test #'eq))))
;;; SSet-Empty -- Interface
;;;
;;; Return true if Set contains no elements, false otherwise.
;;;
(proclaim '(function sset-empty (sset) boolean))
(defun sset-empty (set)
(null (cdr (sset-elements set))))
;;; SSet-Singleton -- Interface
;;;
;;; If Set contains exactly one element, then return it, otherwise return
;;; NIL.
;;;
(proclaim '(function sset-singleton (sset) (or sset-element null)))
(defun sset-singleton (set)
(let ((elements (cdr (sset-elements set))))
(if (and elements (not (cdr elements)))
(car elements)
nil)))
;;; SSet-Subsetp -- Interface
;;;
;;; If Set1 is a (not necessarily proper) subset of Set2, then return true,
;;; otherwise return false.
;;;
(proclaim '(function sset-subsetp (sset sset) boolean))
(defun sset-subsetp (set1 set2)
(let ((el2 (cdr (sset-elements set2))))
(do ((el1 (cdr (sset-elements set1)) (cdr el1)))
((null el1) t)
(let ((num1 (sset-element-number (car el1))))
(loop
(when (null el2) (return-from sset-subsetp nil))
(let ((num2 (sset-element-number (pop el2))))
(when (>= num2 num1)
(when (> num2 num1) (return-from sset-subsetp nil))
(return))))))))
;;; SSet-Equal -- Interface
;;;
;;; Return true if Set1 and Set2 contain the same elements, false otherwise.
;;;
(proclaim '(function sset-equal (sset sset) boolean))
(defun sset-equal (set1 set2)
(do ((el1 (cdr (sset-elements set1)) (cdr el1))
(el2 (cdr (sset-elements set2)) (cdr el2)))
(())
(when (null el1) (return (null el2)))
(when (null el2) (return nil))
(unless (eq (car el1) (car el2)) (return nil))))
;;; Copy-SSet -- Interface
;;;
;;; Return a new copy of Set.
;;;
(proclaim '(function copy-sset (sset) sset))
(defun copy-sset (set)
(let ((res (make-sset)))
(setf (sset-elements res) (copy-list (sset-elements set)))
res))
;;; SSet-Union, SSet-Intersection, SSet-Difference -- Interface
;;;
;;; Perform the appropriate set operation on Set1 and Set2 by destructively
;;; modifying Set1. We return true if Set1 was modified, false otherwise.
;;;
(proclaim '(ftype (function (sset sset) boolean) sset-union sset-intersection
sset-difference))
(defun sset-union (set1 set2)
(let* ((prev-el1 (sset-elements set1))
(el1 (cdr prev-el1))
(changed nil))
(do ((el2 (cdr (sset-elements set2)) (cdr el2)))
((null el2) changed)
(let* ((e (car el2))
(num2 (sset-element-number e)))
(loop
(when (null el1)
(setf (cdr prev-el1) (copy-list el2))
(return-from sset-union t))
(let ((num1 (sset-element-number (car el1))))
(when (>= num1 num2)
(if (> num1 num2)
(let ((new (cons e el1)))
(setf (cdr prev-el1) new)
(setq prev-el1 new changed t))
(shiftf prev-el1 el1 (cdr el1)))
(return))
(shiftf prev-el1 el1 (cdr el1))))))))
;;;
(defun sset-intersection (set1 set2)
(let* ((prev-el1 (sset-elements set1))
(el1 (cdr prev-el1))
(changed nil))
(do ((el2 (cdr (sset-elements set2)) (cdr el2)))
((null el2)
(cond (el1
(setf (cdr prev-el1) nil)
t)
(t changed)))
(let ((num2 (sset-element-number (car el2))))
(loop
(when (null el1)
(return-from sset-intersection changed))
(let ((num1 (sset-element-number (car el1))))
(when (>= num1 num2)
(when (= num1 num2)
(shiftf prev-el1 el1 (cdr el1)))
(return))
(pop el1)
(setf (cdr prev-el1) el1)
(setq changed t)))))))
;;;
(defun sset-difference (set1 set2)
(let* ((prev-el1 (sset-elements set1))
(el1 (cdr prev-el1))
(changed nil))
(do ((el2 (cdr (sset-elements set2)) (cdr el2)))
((null el2) changed)
(let ((num2 (sset-element-number (car el2))))
(loop
(when (null el1)
(return-from sset-difference changed))
(let ((num1 (sset-element-number (car el1))))
(when (>= num1 num2)
(when (= num1 num2)
(pop el1)
(setf (cdr prev-el1) el1)
(setq changed t))
(return))
(shiftf prev-el1 el1 (cdr el1))))))))
;;; SSet-Union-Of-Difference -- Interface
;;;
;;; Destructively modify Set1 to include its union with the difference of
;;; Set2 and Set3. We return true if Set1 was modified, false otherwise.
;;;
(proclaim '(function sset-union-of-difference (sset sset sset) boolean))
(defun sset-union-of-difference (set1 set2 set3)
(let* ((prev-el1 (sset-elements set1))
(el1 (cdr prev-el1))
(el3 (cdr (sset-elements set3)))
(changed nil))
(do ((el2 (cdr (sset-elements set2)) (cdr el2)))
((null el2) changed)
(let* ((e (car el2))
(num2 (sset-element-number e)))
(loop
(when (null el3)
(loop
(when (null el1)
(setf (cdr prev-el1) (copy-list el2))
(return-from sset-union-of-difference t))
(let ((num1 (sset-element-number (car el1))))
(when (>= num1 num2)
(if (> num1 num2)
(let ((new (cons e el1)))
(setf (cdr prev-el1) new)
(setq prev-el1 new changed t))
(shiftf prev-el1 el1 (cdr el1)))
(return))
(shiftf prev-el1 el1 (cdr el1))))
(return))
(let ((num3 (sset-element-number (car el3))))
(when (<= num2 num3)
(unless (= num2 num3)
(loop
(when (null el1)
(do ((el2 el2 (cdr el2)))
((null el2)
(return-from sset-union-of-difference changed))
(let* ((e (car el2))
(num2 (sset-element-number e)))
(loop
(when (null el3)
(setf (cdr prev-el1) (copy-list el2))
(return-from sset-union-of-difference t))
(setq num3 (sset-element-number (car el3)))
(when (<= num2 num3)
(unless (= num2 num3)
(let ((new (cons e el1)))
(setf (cdr prev-el1) new)
(setq prev-el1 new changed t)))
(return))
(pop el3)))))
(let ((num1 (sset-element-number (car el1))))
(when (>= num1 num2)
(if (> num1 num2)
(let ((new (cons e el1)))
(setf (cdr prev-el1) new)
(setq prev-el1 new changed t))
(shiftf prev-el1 el1 (cdr el1)))
(return))
(shiftf prev-el1 el1 (cdr el1)))))
(return)))
(pop el3))))))